;;; init-org.el --- Org mode configuration -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Configuration of select css theme for export Org file
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(with-eval-after-load 'org
  (defun ctrlwei/toggle-org-custom-inline-style ()
    (interactive)
    (unless (featurep 'ox)
      (require 'ox))
    (let ((hook 'org-export-before-processing-hook)
          (fun 'ctrlwei/set-org-html-style))
      (if (memq fun (eval hook))
          (progn
            (remove-hook hook fun 'buffer-local)
            (message "Removed %s from %s" (symbol-name fun) (symbol-name hook)))
        (add-hook hook fun nil 'buffer-local)
        (message "Added %s to %s" (symbol-name fun) (symbol-name hook)))))

  (defun ctrlwei/set-org-html-style (&optional backend)
    (when (or (null backend) (eq backend 'html))
      (let* ((cssdir (expand-file-name "css4org/" ctrlwei-etc-dir))
             (css-choices (directory-files cssdir nil ".css$"))
             (css-files (completing-read-multiple "theme: " css-choices nil t "htmlize.css,")))
        (set (make-local-variable 'org-html-head)
             (with-temp-buffer
               (dolist (css css-files)
                 (insert "\n<style type=\"text/css\">\n<!--/*--><![CDATA[/*><!--*/\n")
                 (insert-file-contents (expand-file-name css cssdir))
                 (goto-char (point-max))
                 (insert "\n/*]]>*/-->\n</style>\n"))
               (buffer-string)))
        (set (make-local-variable 'org-html-head-include-default-style) nil)
        (message "Set custom css style for Org export."))))
  )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Configuration of latex in Org mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(with-eval-after-load 'org
  (setq org-export-with-latex t)
  ;; (setq org-startup-with-latex-preview t)
  (setq org-latex-compiler "xelatex")
  ;; Org code blocks export to PDF
  (setq org-latex-listings 'minted)
  (setq org-latex-minted-options '(("frame" "single")
                                   ("breaklines" "true")
                                   ("breakanywhere" "true")))
  (setq org-latex-pdf-process
        '("xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"
          "xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"
          "xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"))

  ;; see https://emacs-china.org/t/topic/6507/8
  ;; preview latex fragment which include chinese
  (setq org-preview-latex-default-process 'dvisvgm)
  (setq org-preview-latex-process-alist
        '((dvisvgm :programs ("xelatex" "dvisvgm")
                   :description "xdv > svg"
                   :message "you need to install the programs: xelatex and dvisvgm."
                   :use-xcolor t
                   :image-input-type "xdv"
                   :image-output-type "svg"
                   :image-size-adjust (1.7 . 1.5)
                   :latex-compiler ("xelatex -no-pdf -interaction nonstopmode -output-directory %o %f")
                   :image-converter ("dvisvgm %f -n -b min -c %S -o %O")))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Besic configuration for Org mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(with-eval-after-load 'org
  (require 'init-org-publish)

  ;; Do not generate inline css code for code block in html,
  ;; use classname defined in outside css file which specify by :html-htmlized-css-url
  (setq org-html-htmlize-output-type 'css)
  (setq org-imenu-depth 4)
  (setq org-confirm-babel-evaluate nil)
  (setq org-startup-with-inline-images t)
  (org-babel-do-load-languages 'org-babel-load-languages '((shell . t)
                                                           (python . t)
                                                           (emacs-lisp . t)
                                                           (lua . t)
                                                           (java . t)
                                                           (plantuml . t)))

  (setq org-plantuml-jar-path (expand-file-name "plantuml-1.2022.1.jar" ctrlwei-third-party-bin-dir))

  (add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images)
  (add-hook 'org-mode-hook (lambda ()
                             (set (make-local-variable 'electric-indent-functions)
                                  (list (lambda (arg) 'no-indent)))))

  (require 'org-pdfview)
  (add-to-list 'org-file-apps '("\\.pdf\\'" . (lambda (file link) (org-pdfview-open link))))

  (setf (cdr (assoc "\\.x?html?\\'" org-file-apps))
      '(lambda (file link) (eaf-open link)))

  (setq org-buffer-source
        (list :name     "Org Buffer"
              :category 'buffer
              :narrow   ?o
              :face     'consult-buffer
              :history  'buffer-name-history
              :state    #'consult--buffer-state
              :new
              (lambda (name)
                (with-current-buffer (get-buffer-create name)
                  ;; (insert "#+title: " name "\n\n")
                  (org-mode)
                  (consult--buffer-action (current-buffer))))
              :items
              (lambda ()
                (mapcar #'buffer-name
                        (seq-filter
                         (lambda (x)
                           (eq (buffer-local-value 'major-mode x) 'org-mode))
                         (buffer-list))))))

  (unless (featurep 'consult)
    (require 'consult))
  (add-to-list 'consult-buffer-sources 'org-buffer-source 'append)

  )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Besic configuration for agenda
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(setq org-display-custom-times t)
(global-set-key (kbd "M-g a") #'org-agenda)
(global-set-key (kbd "M-g c") #'org-capture)
(with-eval-after-load 'org
  (setq org-agenda-files (list (expand-file-name "~/wspace/org-agenda/")))
  (setq org-todo-keywords '((sequence "TODO(t@/!)" "DOING(i@)" "WAITING(w@/!)" "HOLD(h)" "|" "DONE(d@/!)" "CANCELED(c@/!)")
                            (sequence "REPORT" "BUG" "KNOWNCAUSE" "|" "FIXED")))
  (setq org-tag-alist '((:startgroup . GTD)
                        ("study" . ?s)
                        ("comprehend" . ?c)
                        (:endgroup . GTD)))
  (setq org-time-stamp-custom-formats '("<%Y-%m-%d|%W-%u>" . "<%Y-%m-%d|%W-%u %H:%M>"))
  (setq org-log-into-drawer t)
  (setq org-log-done 'note)
  (setq org-log-reschedule 'note)
  (setq org-log-redeadline 'note)
  (setq org-refile-allow-creating-parent-nodes 'confirm)
  (setq org-refile-targets '((org-agenda-files :maxlevel . 5)))
  (setq org-refile-use-outline-path 'file)
  ;; see https://github.com/raxod502/selectrum/issues/579
  (setq org-outline-path-complete-in-steps nil)
  (setq org-enforce-todo-checkbox-dependencies t)
  (setq org-track-ordered-property-with-tag t)
  (setq org-enforce-todo-dependencies t)
  (setq org-clock-into-drawer "CLOCKING")
  (setq org-global-properties '(("Effort_ALL" . "0:10 0:20 0:30 1:00 2:00 3:00 5:00")))
  (setq org-columns-default-format "%50ITEM(Task) %7TODO(TO DO) %TAGS(Tags) %6CLOCKSUM(Clock) %8Effort(Effort)")

  (setq org-capture-templates `(("t" "Capture for task")
                                ("tt" "Add task" entry
                                 (file+headline ,(expand-file-name "~/wspace/org-agenda/task.org") "Capture")
                                 ,(format "** TODO %%^{Description}\n%%?\n  :LOGBOOK:\n  - Added: %%U\n  :END:")
                                 :empty-lines-before 1)))

  (setq ctrlwei/org-custom-daily-agenda
        ;; Stole from https://gitlab.com/protesilaos/dotfiles/-/blob/master/emacs/.emacs.d/prot-lisp/prot-org.el
        ;; NOTE 2021-12-08: Specifying a match like the following does not
        ;; work.
        ;;
        ;; tags-todo "+PRIORITY=\"A\""
        ;;
        ;; So we match everything and then skip entries with
        ;; `org-agenda-skip-function'.
        `((tags-todo "*"
                     ((org-agenda-skip-function '(org-agenda-skip-if nil '(timestamp)))
                      (org-agenda-skip-function
                       `(org-agenda-skip-entry-if
                         'notregexp ,(format "\\[#%s\\]" (char-to-string org-priority-highest))))
                      (org-agenda-block-separator nil)
                      (org-agenda-overriding-header "Important tasks\n")))
          (todo "WAITING"
                ((org-agenda-block-separator nil)
                 (org-agenda-overriding-header "\nTask on suspension\n")))
          (agenda "" (
                      (org-agenda-time-grid nil)
                      (org-agenda-start-on-weekday nil)
                      (org-agenda-span 1)
                      (org-agenda-show-all-dates nil)
                      (org-scheduled-past-days 365)
                      ;; ;; Excludes today's scheduled items
                      (org-scheduled-delay-days 1)
                      (org-agenda-block-separator nil)
                      (org-agenda-entry-types '(:scheduled))
                      (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
                      (org-agenda-day-face-function (lambda (date) 'org-agenda-date))
                      (org-agenda-format-date "")
                      (org-agenda-overriding-header "\nPending scheduled tasks")))
          (agenda "" ((org-agenda-span 1)
                      (org-deadline-warning-days 0)
                      (org-agenda-block-separator nil)
                      (org-scheduled-past-days 0)
                      ;; We don't need the `org-agenda-date-today'
                      ;; highlight because that only has a practical
                      ;; utility in multi-day views.
                      (org-agenda-day-face-function (lambda (date) 'org-agenda-date))
                      (org-agenda-format-date "%A %-e %B %Y (W%W)")
                      (org-agenda-overriding-header "\nToday's agenda\n")))
          (agenda "" ((org-agenda-start-on-weekday nil)
                      (org-agenda-start-day "+1d")
                      (org-agenda-span 3)
                      (org-deadline-warning-days 0)
                      (org-agenda-block-separator nil)
                      (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
                      (org-agenda-overriding-header "\nNext three days\n")))
          (agenda "" ((org-agenda-time-grid nil)
                      (org-agenda-start-on-weekday nil)
                      ;; We don't want to replicate the previous section's
                      ;; three days, so we start counting from the day after.
                      (org-agenda-start-day "+4d")
                      (org-agenda-span 14)
                      (org-agenda-show-all-dates nil)
                      (org-deadline-warning-days 0)
                      (org-agenda-block-separator nil)
                      (org-agenda-entry-types '(:deadline))
                      (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
                      (org-agenda-overriding-header "\nUpcoming deadlines (+14d)\n"))))
        )

  (add-to-list 'org-agenda-custom-commands
               `("w" "Daily agenda and top priority tasks"
                 ,ctrlwei/org-custom-daily-agenda
                 ((org-agenda-fontify-priorities nil)
                  (org-agenda-dim-blocked-tasks nil))))

  (defun ctrlwei/move-cursor-in-agenda ()
    "Move cursor to current date header in Org agenda view."
    (unless (search-forward (format-time-string "%A %-e %B %Y (W%W)" (current-time)) nil t)
      (search-forward (org-agenda-format-date-aligned (calendar-current-date)) nil t)))

  (add-hook 'org-agenda-finalize-hook #'ctrlwei/move-cursor-in-agenda)

  (defun ctrlwei/org-schedule (orig-fun arg &optional time)
    "Add default hours and minutes when insert schedule date."
    (let ((old-time (symbol-function #'org-read-date)))
      (cl-letf (((symbol-function #'org-read-date)
                 #'(lambda (&optional a b c d default-time f g)
                     (let ((default-time (or default-time
                                             (format-time-string "%H:%M" (current-time)))))
                       (apply old-time a b c d f default-time g)))))
        (apply orig-fun arg time))))
  ;; (advice-add #'org-schedule :around #'ctrlwei/org-schedule)

  (defun ctrlwei/org-id-create-all ()
    (interactive)
    (save-excursion
      (goto-char (point-max))
      (while (outline-previous-heading)
        (org-id-get-create))))
)

(provide 'init-org)
;;; init-org.el ends here
